package com.tang.javaSwingCaculate.Stack;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author tmh
 * @date 2022/12/4 22:03
 * @description 中辍表达式转换为后辍表达式
 */
@Data
@Slf4j
public class InToPost {
    public static final ArrayList<String> list = new ArrayList();

    public static final HashMap<Integer, String> map = new HashMap<>();
    public static Integer OPERATE_COUNT = 0;

    /**
     * opStack:存放操作过程中的运算符
     */
    private MyStack opStack;

    /**
     * outStack:存放最后的后辍表达式
     */
    private MyStack outStack;

    /**
     * input:表示为中辍表达式，需要被转换
     */
    private String input;

    public InToPost(String input) {
        this.input = input;
        opStack = new MyStack(100);
        outStack = new MyStack(100);
    }

    /**
     * 中辍表达式转为后辍表达式
     */
    public void formatTrans() {
        // 定义正则表达式，用于匹配数字、小数点、运算符和括号
        String regex = "\\d+(\\.\\d+)?|[+\\-*/()]";

        // 创建正则表达式模式，并利用该模式匹配字符串
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        // 使用Matcher对象的find()方法逐个查找匹配的子字符串
        while (matcher.find()) {
            // 获取匹配到的子字符串
            list.add(matcher.group());
        }

        map.put(++OPERATE_COUNT, input);//用于实现历史记录功能

        String[] tokens = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            tokens[i] = list.get(i);
        }

        log.info("中辍表达式的结果" + list.toString());

        list.clear();//清空数组

        for (String ch : tokens) {
            switch (ch) {
                case "+":
                case "-":
                    operationOpStack(ch, 1);
                    break;
                case "*":
                case "/":
                    operationOpStack(ch, 2);
                    break;
                case "(":
                    opStack.push(ch);
                    break;
                case ")":
                    operationPattern();
                    break;
                default:
                    outStack.push(ch);
                    break;
            }
        }
        while (!opStack.isMyStackEmpty()) {
            outStack.push(opStack.pop());
        }
    }

    /**
     * 对操作符号的运算
     *
     * @param opThis   当前的操作符
     * @param precise1 优先级 1代表+，-的优先级  2代表*，/的优先级
     */
    public void operationOpStack(String opThis, int precise1) {
        //当opStack不为空时，开始进行判断
        while (!opStack.isMyStackEmpty()) {
            String opTop = opStack.pop();
            if (opTop.equals("(")) {
                opStack.push(opTop);
                break;
            } else {
                int precise2;
                if (opTop.equals("+") || opTop.equals("-")) {
                    precise2 = 1;
                } else {
                    precise2 = 2;
                }
                //当前比较得运算符优先级比栈顶元素优先级高时入栈
                if (precise1 > precise2) {
                    opStack.push(opTop);
                    break;
                } else {
                    outStack.push(opTop);
                }
            }
        }
        opStack.push(opThis);
    }

    /**
     * 对（ 的具体操作
     * 如果遇到了）,那么就把（之前的运算符出栈放到outStack里面
     */
    public void operationPattern() {
        while (!opStack.isMyStackEmpty()) {
            String c = opStack.pop();
            if (c.equals("(")) {
                break;
            } else {
                outStack.push(c);
            }

        }
    }

    /**
     * 计算出最后后缀表达式的四则运算表达式的结果
     *
     * @return 运算结果
     */
    public Double calculateResult() {
        MyStackDouble result = new MyStackDouble(outStack.length());
        log.info("后缀表达式结果" + outStack.toString());
        int myStackLength = outStack.length();
        if (myStackLength == 0) {
            log.info("用户未输入任何有效值，返回为空--null--");
            return null;
        }
        //遇到操作符就从result栈里面弹出两个元素来进行运算
        for (int i = 0; i < myStackLength; i++) {
            if ("+".equals(outStack.getStackArray()[i])) {
                result.push(result.pop() + result.pop());
            } else if ("-".equals(outStack.getStackArray()[i])) {
                result.push(-result.pop() + result.pop());
            } else if ("*".equals(outStack.getStackArray()[i])) {
                result.push(result.pop() * result.pop());
            } else if ("/".equals(outStack.getStackArray()[i])) {
                Double temp1 = result.pop();
                Double temp2 = result.pop();
                result.push(temp2 / temp1);
            } else {
                result.push(Double.parseDouble(outStack.getStackArray()[i]));
            }
        }
        return result.pop();
    }


}
